﻿using LJ.EventBus.Abstractions;
using LJ.EventBus.Data;
using LJ.EventBus.HornedSerpent.Transport.Abstractions;
using LJ.IdGenerator.Abstractions;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LJ.EventBus.HornedSerpent.Internal;


public class EventBusPublisher( IIdGenerator idGenerator, IEventBusMessageSerializer eventBusMessageSerializer, IEventBusTransport eventBusTransport) : IEventBusPublisher
{
    private readonly IIdGenerator _idGenerator = idGenerator;
    private readonly IEventBusMessageSerializer _eventBusMessageSerializer = eventBusMessageSerializer;
    private readonly IEventBusTransport _eventBusTransport = eventBusTransport;

    public async Task PublishAsync<T>(string name, T value, CancellationToken cancellationToken = default)
    {
        var headers = new Dictionary<string, string?>
        {
        };
        await PublishInternalAsync(name, value, headers, cancellationToken);
    }

    public async Task PublishAsync<T>(string name, T value, IDictionary<string, string?> headers, CancellationToken cancellationToken = default)
    {
        await PublishInternalAsync(name, value, headers, cancellationToken);
    }

    private async Task PublishInternalAsync<T>(string name, T value, IDictionary<string, string?> headers, CancellationToken cancellationToken = default)
    {

        ArgumentNullException.ThrowIfNull(value, nameof(value));

        if (string.IsNullOrEmpty(name)) throw new ArgumentNullException(nameof(name));


        if (!headers.ContainsKey(EventBusHeaders.MessageId))
        {
            var messageId = _idGenerator.Create().ToString();
            headers.Add(EventBusHeaders.MessageId, messageId);
        }

        headers.Add(EventBusHeaders.MessageName, name);

        var publishTime = DateTimeOffset.Now;

        headers.Add(EventBusHeaders.SentTime, publishTime.ToString(CultureInfo.InvariantCulture));

        var message = new EventBusMessage(headers, value);

        var transportData = new EventBusTransportData(headers, _eventBusMessageSerializer.ToBytes(_eventBusMessageSerializer.Serialize(message.Value)));

        await _eventBusTransport.SendAsync(transportData, cancellationToken);

    }

}
